import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Calendar;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;


public class CalendarWidget extends JPanel {
	private Application controller;
	/**Najważniejszy element kalendarza - tabela zawierająca w komórkach dni miesiąca*/
	private JTable table;
	private JButton buttonNextMonth;
	private JButton buttonPrevMonth;
	private JButton buttonNextYear;
	private JButton buttonPrevYear;
	private JLabel month;
	private JLabel year;
	private JPanel uppanel;
	private JPanel downpanel;
	private JPanel tpanel;
	SelectionListener sListener;
	private DefaultTableModel model;
	
	Calendar currentDate;
	

/**
 * Nasłuchuje czy zmieniono zaznaczenie w tabeli. Jeżeli tak to informuje o tym główny kontroler wywołując newDateSelected(Calendar start, Calendar end).
 * @author krzys
 *
 */
		public class SelectionListener implements ListSelectionListener 
		{

		    SelectionListener() 
		    {
		        
		    }
		    public void valueChanged(ListSelectionEvent e) 
		    {
		    	if (e.getValueIsAdjusting()) {
	                return;
	            }
		    	controller.newDateSelected(getStartDate(), getEndDate());
		    }

		}
	/**
	 * Nasłuchuje naciśnięcia przycisków służących do zmiany roku/miesiąca.
	 * @author krzys
	 *
	 */
	class Events implements ActionListener
	{
		public void actionPerformed(ActionEvent evt) 
		{
			if (evt.getSource() == buttonPrevMonth)
			{
				currentDate.set(Calendar.MONTH, currentDate.get(Calendar.MONTH)-1);
				month.setText(monthPl(currentDate.get(Calendar.MONTH)));
			}
			else if (evt.getSource() == buttonNextMonth)
			{
				currentDate.set(Calendar.MONTH, currentDate.get(Calendar.MONTH)+1);
				month.setText(monthPl(currentDate.get(Calendar.MONTH)));

			}
			else if (evt.getSource() == buttonPrevYear)
			{
				currentDate.set(Calendar.YEAR, currentDate.get(Calendar.YEAR)-1);
				year.setText(String.valueOf(currentDate.get(Calendar.YEAR)));

			}
			else if (evt.getSource() == buttonNextYear)
			{
				currentDate.set(Calendar.YEAR, currentDate.get(Calendar.YEAR)+1);
				year.setText(String.valueOf(currentDate.get(Calendar.YEAR)));
			}
			currentDate.set(Calendar.DAY_OF_MONTH, 1);
			fillCalendar();
			controller.newDateSelected(getStartDate(), getEndDate());
		}

	}
	/**
	 * Metoda uaktualnia stan kalendarza.
	 */
	protected void fillCalendar()
	{	
		table.getSelectionModel().removeListSelectionListener(sListener);
		table.getColumnModel().getSelectionModel().removeListSelectionListener(sListener);
		
		int i=0,days,rs=0,cs=0;
		String [][] data = new String[7][7];
		String col[] = {"Pn","Wt","Śr","Cz","Pt","So","Nd"};
		Calendar c = (Calendar)currentDate.clone();
		model = new DefaultTableModel(data, col);
		days=c.getActualMaximum(Calendar.DATE);
		c.set(Calendar.DAY_OF_MONTH, 1);
		int pom=(c.get(Calendar.DAY_OF_WEEK)+5)%7;
		
			for ( i=pom; i<pom+days; i++)
			{
				
				if (currentDate.get(Calendar.DAY_OF_MONTH)==c.get(Calendar.DAY_OF_MONTH))
				{
					rs=i/7;
					cs=i%7;
				}
				
				model.setValueAt(c.get(Calendar.DAY_OF_MONTH),i/7, i%7);
				c.set(Calendar.DAY_OF_MONTH, c.get(Calendar.DAY_OF_MONTH)+1);
			}
		table.setModel(model);
		table.changeSelection(rs, cs, false, false);
		table.getSelectionModel().addListSelectionListener(sListener);
		table.getColumnModel().getSelectionModel().addListSelectionListener(sListener);
		
		
	}
	/**
	 * Inicjalizuje obiekt klasy CalendarWidget oraz ustawia podaną datę.
	 * @param controller Referencja do głównego kontrolera
	 * @param selectedDate	Data, która ma zostać zaznaczona przy tworzeniu obiektu.
	 */
	public CalendarWidget (Application controller, Calendar selectedDate)
	{
		super();
		this.controller=controller;
		sListener = new SelectionListener ();
		currentDate = (Calendar)selectedDate.clone();
		
		uppanel = new JPanel ();
		downpanel = new JPanel();
		tpanel = new JPanel();
		uppanel.setLayout(new FlowLayout());
		tpanel.setLayout(new BorderLayout());
		setLayout(new BorderLayout());
		uppanel.add(buttonPrevMonth = new JButton ("<"));
		uppanel.add(month = new JLabel (monthPl(currentDate.get(Calendar.MONTH))));
		uppanel.add(buttonNextMonth = new JButton (">"));
		downpanel.add(buttonPrevYear = new JButton("<"));
		downpanel.add(year = new JLabel (String.valueOf(currentDate.get(Calendar.YEAR))));
		downpanel.add(buttonNextYear = new JButton(">"));
		
		Events e = new Events ();
		buttonPrevMonth.addActionListener(e);
		buttonNextMonth.addActionListener(e);
		buttonPrevYear.addActionListener(e);
		buttonNextYear.addActionListener(e);
		buttonPrevMonth.setMnemonic(KeyEvent.VK_NUMPAD4);
		buttonNextMonth.setMnemonic(KeyEvent.VK_NUMPAD6);
		buttonPrevYear.setMnemonic(KeyEvent.VK_NUMPAD1);
		buttonNextYear.setMnemonic(KeyEvent.VK_NUMPAD3);
		table = new JTable ();
		fillCalendar();
		table.setCellSelectionEnabled(true);
		for (int i=0 ; i<7; i++)
		table.getColumnModel().getColumn(i).setPreferredWidth(30);
		tpanel.add(table.getTableHeader(),BorderLayout.NORTH);
		tpanel.add(table);
		add(uppanel,BorderLayout.NORTH);
		add(tpanel,BorderLayout.CENTER);
		add(downpanel,BorderLayout.SOUTH);	
		setPreferredSize(new Dimension(250,200));
	}
	/**
	 * Tłumaczy na język polski nazwy miesięcy.
	 * @param  m Numer miesiąca.
	 * @return Obiekt klasy String zawierający polską nazwę miesiąca.
	 */
	private String monthPl(int m)
    {
    	String month = new String();
    	switch (m)
    	{
    	case Calendar.JANUARY: month = "STYCZEŃ"; break;
    	case Calendar.FEBRUARY: month = "LUTY"; break;
    	case Calendar.MARCH: month = "MARZEC"; break;
    	case Calendar.APRIL: month = "KWIECIEŃ"; break;
    	case Calendar.MAY: month= "MAJ"; break;
    	case Calendar.JUNE: month = "CZERWIEC"; break;
    	case Calendar.JULY: month = "LIPIEC"; break;
    	case Calendar.AUGUST: month = "SIERPIEŃ"; break;
    	case Calendar.SEPTEMBER: month = "WRZESIEŃ"; break;
    	case Calendar.OCTOBER: month = "PAŹDZIERNIK"; break;
    	case Calendar.NOVEMBER: month = "LISTOPAD"; break;
    	case Calendar.DECEMBER: month = "GRUDZIEŃ"; break;
    	}
    	return month;
    }
	/**
	 * Oblicza aktualnie zaznaczoną początkową datę.
	 * @return	Data początkowa.
	 */
	private Calendar getStartDate()
	{
		int x = table.getSelectedColumn();
		int y = table.getSelectedRow();
		Calendar c = (Calendar)currentDate.clone();
		Integer day = (Integer)model.getValueAt(y, x);
		try{
			c.set(Calendar.DATE, day.intValue());
			}
		catch (NullPointerException e)
		{
			fillCalendar();
		}
		return c;
	}
	/**
	 * Oblicza aktualnie zaznaczoną końcową datę.
	 * @return Data końcowa.
	 */
	private Calendar getEndDate()
	{
		int x = table.getSelectedColumn()+table.getSelectedColumnCount()-1;
		int y = table.getSelectedRow();
		Calendar c = (Calendar)currentDate.clone();
		Integer day = (Integer)model.getValueAt(y, x);
		try{
		c.set(Calendar.DATE, day.intValue());
		}
		catch (NullPointerException e)
		{
			fillCalendar();
		}
		return c;
	}
	
}
